﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Engine.Graphics
{
    public enum MovementState
    {
        Standing,
        Walking,
        Jumping,
        Ducking,
        Spinning,
        Dashing
    }

    public class AnimatedSprite : Sprite
    {
        #region Fields
        Dictionary<MovementState, Animation> animations;
        Dictionary<MovementState, Texture2D> textures;

        public Dictionary<string, Animation> additionalAnimations;
        public Dictionary<string, Texture2D> additionalTextures;

        List<string> playOnceStack;

        MovementState currentMovement;

        bool isAnimating;
        
        #endregion

        #region Properties
        public int DefaultWidth;
        public int DefaultHeight;

        public Dictionary<MovementState, Texture2D> Textures
        {
            get { return textures; }
        }

        public Dictionary<MovementState, Animation> Animations
        {
            get { return animations; }
        }

        public bool PlaysAdditionalAnimation { get { return playOnceStack.Count > 0; } }

        public Animation CurrentAnimation
        {
            get
            {
                if (PlaysAdditionalAnimation)
                    return additionalAnimations[playOnceStack[playOnceStack.Count - 1]];
                else
                    return animations[CurrentMovement];
            }
        }

        public string CurrentAnimationName
        {
            get
            {
                if (PlaysAdditionalAnimation)
                    return playOnceStack[playOnceStack.Count - 1];
                else
                    return "";
            }
        }

        public MovementState CurrentMovement
        {
            get { return currentMovement; }
            set { currentMovement = value; }
        }

        public Texture2D CurrentTexture
        {
            get { return textures[currentMovement]; }
        }

        public bool IsAnimating
        {
            get { return isAnimating; }
            set { isAnimating = value; }
        }

        public override Vector2 Origin
        {
            get
            {
                if (IsCentered)
                    return new Vector2(animations[currentMovement].FrameWidth / 2, animations[currentMovement].FrameHeight/2);

                return Vector2.Zero;
            }
        }

        public override int Width
        {
            get { return animations[currentMovement].FrameWidth * (int)Scale.X; }
        }
        public override int Height
        {
            get { return animations[currentMovement].FrameHeight * (int)Scale.Y; }
        }
        #endregion

        #region Constructors

        public AnimatedSprite()
        {
            textures = new Dictionary<MovementState, Texture2D>();
            animations = new Dictionary<MovementState, Animation>();
            additionalAnimations = new Dictionary<string, Animation>();
            additionalTextures = new Dictionary<string, Texture2D>();
            playOnceStack = new List<string>();

            currentMovement = MovementState.Standing;
            Perspective = true;
            IsAnimating = true;

            DefaultHeight = 0;
            DefaultWidth = 0;
        }

        public AnimatedSprite(Dictionary<MovementState, Texture2D> _textures, Dictionary<MovementState, Animation> _animations):base(_textures[MovementState.Standing], true)
        {
            textures = _textures;
            animations = new Dictionary<MovementState, Animation>();
            foreach (MovementState name in _animations.Keys)
            {
                animations.Add(name, (Animation)_animations[name].Clone());
            }

            additionalAnimations = new Dictionary<string, Animation>();
            additionalTextures = new Dictionary<string, Texture2D>();
            playOnceStack = new List<string>();

            currentMovement = MovementState.Standing;
            SourceRectangle = animations[currentMovement].CurrentFrameRect;
            Perspective = true;
            IsAnimating = true;

            DefaultWidth = animations[currentMovement].CurrentFrameRect.Width;
            DefaultHeight = animations[currentMovement].CurrentFrameRect.Height;
        }

        #endregion
        public override void OnAdd(GameObject _gameObject)
        {
            base.OnAdd(_gameObject);
        }

        public override void OnRemove()
        {
            base.OnRemove();
        }

        public override void Update(GameTime gameTime)
        {
            if (isAnimating)
            {
                if (PlaysAdditionalAnimation)
                {
                    string currentAnim = playOnceStack[playOnceStack.Count - 1];
                    Animation currentStackAnimation = additionalAnimations[currentAnim];
                    currentStackAnimation.Update(gameTime);
                    if (currentStackAnimation.IsFinished)
                        playOnceStack.RemoveAt(playOnceStack.Count - 1);

                    texture = additionalTextures[currentAnim];
                    SourceRectangle = additionalAnimations[currentAnim].CurrentFrameRect;
                    DrawOffset = additionalAnimations[currentAnim].DrawingOffset;
                }
                else
                {
                    animations[currentMovement].Update(gameTime);
                    texture = textures[CurrentMovement];
                    SourceRectangle = animations[currentMovement].CurrentFrameRect;
                    DrawOffset = animations[currentMovement].DrawingOffset;
                }
            }
        }

        #region Public Methods
        public void Reset()
        {
                animations[currentMovement].Reset();
        }

        public void SetAnimation(MovementState _state)
        {
            currentMovement = _state;
            //texture = textures[currentMovement];
            //Reset();
        }

        public void PlayOnce(string _name, bool _append = false)
        {
            if (additionalAnimations.ContainsKey(_name))
            {
                additionalAnimations[_name].Reset();

                if (_append)
                    playOnceStack.Insert(0, _name);
                else
                    playOnceStack.Add(_name);
            }
            else
            {
                Console.WriteLine("Additional Animation: " + _name + " not found");
            }
        }

        public void StopAdditionalAnimation()
        {
            if (PlaysAdditionalAnimation)
                playOnceStack.RemoveAt(playOnceStack.Count - 1);
        }

        public object Clone()
        {
            AnimatedSprite sprite = new AnimatedSprite(textures, animations);
            return sprite;
        }

        #endregion
    }
}
